home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / c-runtime / dispatch / core.c next >
Encoding:
C/C++ Source or Header  |  1992-08-18  |  35.6 KB  |  1,286 lines

  1. /* -*-c-*- */
  2.  
  3. /* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
  4.  
  5. This file is part of GNU CC.
  6.  
  7. GNU CC is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2, or (at your option)
  10. any later version.
  11.  
  12. GNU CC is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with GNU CC; see the file COPYING.  If not, write to
  19. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21. /* As a special exception, if you link this library with files
  22.    compiled with GCC to produce an executable, this does not cause
  23.    the resulting executable to be covered by the GNU General Public License.
  24.    This exception does not however invalidate any other reasons why
  25.    the executable file might be covered by the GNU General Public License.  */
  26.  
  27. /* 
  28.   $Header: /usr/user/dennis_glatting/ObjC/c-runtime/dispatch/RCS/core.c,v 1.2 1992/08/18 04:46:58 dglattin Exp $
  29.   $Author: dglattin $
  30.   $Date: 1992/08/18 04:46:58 $
  31.   $Log: core.c,v $
  32.  * Revision 1.2  1992/08/18  04:46:58  dglattin
  33.  * Saving a working version before release.
  34.  *
  35.  * Revision 1.1  1992/04/13  11:43:08  dennisg
  36.  * Initial revision
  37.  *
  38. */
  39.  
  40. #include    <assert.h>
  41. #include    <ctype.h>
  42. #include    <memory.h>
  43.  
  44. #include    <hash.h>
  45. #include    <objc.h>
  46. #include    <objcP.h>
  47. #include    <objc-proto.h>
  48. #include    <objc-protoP.h>
  49.  
  50.  
  51. #define MODULE_HASH_SIZE            32          /* Initial module hash table 
  52.                                                                                                     size.  Value really doesn't
  53.                                                   matter. */
  54.                                                                                             
  55.  
  56. #define CLASS_HASH_SIZE             32          /* Initial number of buckets 
  57.                                                                                                     size of class hash table. */  
  58.  
  59.  
  60. /* Forward declare some functions. */
  61. id            objc_object_create (Class_t),
  62.               objc_object_dispose (id),
  63.               objc_object_realloc (id, u_int),
  64.               objc_object_copy (id);
  65. void          objc_error (id aObject, const char* fmt, va_list ap);
  66. static id     nilMethodIMP (id, SEL, ...);
  67. static id     returnErrorStaticIMP (id, SEL, ...);
  68. static IMP    handleRuntimeError (id, SEL);
  69. static void   initializeDispatchTables (void);
  70. static SEL    recordSelector (const char*);
  71. static void   recordMethodsFromClass (Class_t);
  72. static void   recordMethodsFromMethodList (MethodList_t);
  73. static void        initializeClass (const char*);
  74.  
  75.  
  76. /*
  77.  * This is a hash table of Class_t structures. 
  78.  *
  79.  * At initialization the executable is searched for all Class_t structures. 
  80.  * Since these structures are created by the compiler they are therefore
  81.  * located in the TEXT segment.  
  82.  *
  83.  * A identical structure is allocated from the free store and initialized from
  84.  * its TEXT counterpart and placed in the hash table using the TEXT part as
  85.  * its key. 
  86.  *
  87.  * Since the free store structure is now writable, additional initialization
  88.  * takes place such as its "info" variable, method cache allocation, and
  89.  * linking of all of its method and ivar lists from multiple implementations. 
  90.  */
  91.     Cache_t    classHash = NULL;
  92.  
  93. /*
  94.  * This variable is a flag used within the messaging routines.  If a
  95.  * application sets it to !0 then the messager will print messages sent to
  96.  * objects. 
  97.  */
  98.     BOOL  objc_trace = NO;
  99.  
  100. /* This mutex provides a course lock for method dispatch. */
  101.     MUTEX    runtimeMutex;
  102.  
  103. /*
  104.  * This hash table is used by the initialization routines.  When the
  105.  * constructor function (__objc_execClass) is called it is passed a pointer
  106.  * to a module structure.  That pointer is stored in this table and its
  107.  * contents are processed in __objcInit(). 
  108.  */
  109.     Cache_t    moduleHash = NULL;
  110.  
  111. /*
  112.  * This flag is used by the messager routines to determine if the run-time
  113.  * has been initialized.  If the run-time isn't initialized then a
  114.  * initialization clean up routine is called. 
  115.  */
  116. static int    runtimeInitialized = 0;
  117.  
  118. /*
  119.  * Records that hold pointers to arrays of records.  The terminal records are
  120.  * method implementations. 
  121.  *
  122.  * The size of the first record is the number of unique classes in the
  123.  * executable.  The second is the number of selectors. 
  124.  *
  125.  * The second record conatins methods that are visible to the class -- that is,
  126.  * methods that are not overriden from the classt to the root object. 
  127.  *
  128.  * The cache pointers of class and meta class structures point to one of these
  129.  * records. 
  130.  */
  131. static Record_t    instanceMethodRecord    = NULL;
  132. static Record_t    factoryMethodRecord    = NULL;
  133.  
  134. /*
  135.  * This structure is used to translate between selectors and their ASCII
  136.  * representation.  A NULL terminated array of char*,
  137.  * OBJC_SELECTOR_REFERENCES, is passed to the constructor routine: 
  138.  * __objc_execClass(). That routine places entries from that array into this
  139.  * structure.  The location within OBJC_SELECTOR_REFERENCES where the string
  140.  * was taken from is replaced with a small integer, the index into the array
  141.  * inside selectorTranslateTable.  That integer then becomes the selector. 
  142.  *
  143.  * Selectors begin at 1 to numEntries.  A selector outside of that range is
  144.  * considered an error.  The selector integers are used as the first index
  145.  * into the instanceMethodRecord and factoryMethodRecord arrays. 
  146.  */
  147. static Record_t    selectorRecord = NULL;
  148.  
  149. /*
  150.  * This data structure is used in the special case where usual fatal error
  151.  * functions are called but have been overridden in a class.  The value
  152.  * returned by that function is returned to the calling object.  errorStatic
  153.  * holds the returned value until it is retrieved by returnErrorStaticIMP
  154.  * which returns it to the calling function. 
  155.  */
  156. static id    errorStatic;
  157.  
  158.  
  159. /* Given a class and selector, return the selector's implementation. */
  160. static inline IMP    
  161. getIMP (Class_t aClass, SEL aSel) {
  162.  
  163.   IMP    theIMP = NULL;
  164.  
  165.  
  166.   theIMP = record_get (getClassNumber (aClass),
  167.                record_get ((u_int)aSel, *aClass->cache));
  168.  
  169.   return theIMP;
  170. }
  171.  
  172.  
  173. static inline char*
  174. strdup (const char* str) {
  175.  
  176.   char*    newStr = malloc (strlen (str) + 8);
  177.     
  178.     
  179.   assert (newStr);
  180.   sprintf (newStr, "%s", str);
  181.     
  182.   return newStr;
  183. }
  184.  
  185.  
  186. /*
  187.  * This function is called by constructor functions generated for each module
  188.  * compiled.  
  189.  *
  190.  * The purpose of this function is to gather the module pointers so that they
  191.  * may be processed by the initialization clean up routine. 
  192.  */
  193. void 
  194. __objc_execClass (Module_t aModule) {
  195.  
  196.  
  197.   assert(aModule->size == sizeof (Module));
  198.   DEBUG_PRINTF (stderr, "received load module: %s\n",aModule->name);
  199.  
  200.   /* Allocate the module hash table if it doesn't exist. */
  201.   if (!moduleHash)
  202.     moduleHash = hash_new (MODULE_HASH_SIZE, 
  203.                                                     (HashFunc)intHash, (CompareFunc)intCmp);
  204.   
  205.   /* Save the module pointer for later processing. */
  206.   hash_add (&moduleHash, aModule, aModule);
  207. }
  208.  
  209.  
  210. /*
  211.  * This function is called by the executable before main ().  Its purpose is
  212.  * to initialize the ObjC run-time system. 
  213.  */
  214. void  
  215. objcInitCleanup (void) {
  216.  
  217.     MetaClass_t    classObject;
  218.   CacheNode_t aNode;
  219.   u_int       i;
  220.  
  221.  
  222.   /* Header file data structure hack test. */
  223.   assert(sizeof (Class) == sizeof (MetaClass));
  224.  
  225.  /* Allocate and initialize the mutex. */
  226.      MUTEX_ALLOC( &runtimeMutex );
  227.     MUTEX_INIT( runtimeMutex );
  228.  
  229.   /* Enable malloc debugging. This'll slow'er down! */
  230. #ifdef DEBUG
  231.   malloc_debug (62);
  232. #endif
  233.  
  234.   /* Allocate the selector translation record. */
  235.     selectorRecord = record_new ();
  236.  
  237.     /* For all of the modules collected in the constructor function.
  238.         Make a first pass through the modules and process some of the data. */
  239.     for (aNode = hash_next (moduleHash, NULL); aNode;
  240.         aNode = hash_next (moduleHash, aNode)) {
  241.         Module_t    aModule = aNode->theValue;
  242.       Symtab_t    theSymtab = aModule->symtab;
  243.       SEL       *(*selectors)[] = (SEL* (*)[])theSymtab->refs;
  244.  
  245.       DEBUG_PRINTF (stderr, "parsing load module: %s\n",aModule->name);
  246.         for (i = 0; i < theSymtab->cls_def_cnt; ++i) {
  247.         Class_t theClass = (Class_t)theSymtab->defs[ i ];
  248.     
  249.         /* Make sure we have what we think. */
  250.         assert(theClass->info & CLS_CLASS);
  251.         assert(theClass->isa->info & CLS_META);
  252.             
  253.         DEBUG_PRINTF (stderr, "phase 1, processing class: %s\n", theClass->name);
  254.  
  255.         /* Store the class in the class table and assign class numbers. */
  256.             addClassToHash(theClass);
  257.             
  258.         /* Store all of the selectors in the class and meta class. */
  259.         recordMethodsFromClass (theClass);
  260.         recordMethodsFromClass ((Class_t)theClass->isa);
  261.         
  262.         /* Initialize the cache pointers. */
  263.         theClass->cache = &instanceMethodRecord;
  264.         theClass->isa->cache = &factoryMethodRecord;
  265.         }
  266.  
  267.         /* Replace referenced selectors. */
  268.       if (selectors)
  269.         for(i = 0; (*selectors)[ i ]; ++i)
  270.           (*selectors)[ i ] = recordSelector ((const char*)(*selectors)[ i ]);
  271.     }
  272.  
  273.     /* Get the meta class object for connection processing. */
  274.     classObject = objc_getMetaClass( "Object" );
  275.   assert( classObject );
  276.   assert( classObject->info & CLS_META );
  277.  
  278.     /* Connect the classes together. */ 
  279.     for (aNode = hash_next (classHash, NULL); aNode;
  280.         aNode = hash_next (classHash, aNode)) {
  281.         
  282.     Class_t    theClass = aNode->theValue;
  283.  
  284.     /* Make sure we have what we think. */
  285.     assert(theClass->info & CLS_CLASS);
  286.     assert(theClass->isa->info & CLS_META);
  287.             
  288.     DEBUG_PRINTF (stderr, "phase 2, processing class: %s\n", theClass->name);
  289.  
  290.         /* The isa pointer of all meta classes point to Object's meta class. */
  291.         theClass->isa->isa = classObject;
  292.  
  293.     /* Assign super class pointers */
  294.     if (theClass->super_class)
  295.       theClass->super_class = objc_getClass ((char*)theClass->super_class);
  296.     if (theClass->isa->super_class)
  297.       theClass->isa->super_class = theClass->super_class->isa;
  298.     }
  299.  
  300.   /* Interconnect the category information. */
  301.     for (aNode = hash_next (moduleHash, NULL); aNode;
  302.         aNode = hash_next (moduleHash, aNode)) {
  303.  
  304.     Module_t  theModule = aNode->theValue;
  305.     Symtab_t  theSymtab = theModule->symtab;
  306.     int       j;
  307.  
  308.     DEBUG_PRINTF (stderr, "processing categories from: %s\n", theModule->name);
  309.  
  310.     /*
  311.      * Connect the category information. 
  312.      *
  313.      * Place instance and class category methods at the head of the
  314.      * class's method list. 
  315.      */
  316.     for (j = 0; j < theSymtab->cat_def_cnt; ++j) {
  317.       Category_t  theCategory = theSymtab->defs[ j + theSymtab->cls_def_cnt ];
  318.     
  319.       /* Do instance methods. */
  320.       if (theCategory->instance_methods)
  321.         addMethodsToClass (objc_getClass (theCategory->class_name),
  322.                               theCategory->instance_methods);
  323.       
  324.       /* Do class methods. */
  325.       if (theCategory->class_methods)
  326.         addMethodsToClass 
  327.           ((Class_t)objc_getMetaClass (theCategory->class_name),
  328.             theCategory->class_methods);
  329.     }
  330.   }
  331.  
  332.   initializeDispatchTables();
  333.  
  334.   /* Prevent future calls to the clean up routine. */
  335.   runtimeInitialized = 1;
  336.  
  337.   /* Print out class tables if debugging. */
  338.   DEBUG_PRINTF (stderr, "dump of class tables from objcInit()\n");
  339.   debug_dump_classes();
  340.  
  341. }
  342.  
  343.  
  344. IMP  
  345. objc_msgSend (id theReceiver, SEL aSel) {
  346.  
  347.   /*
  348.    * A method is always called by the compiler.  If a method wasn't
  349.    * found then supply a default. 
  350.    */
  351.   IMP  theIMP = nilMethodIMP;
  352.  
  353.  
  354.   /* The run time must be initialized at this point.
  355.      Otherwise we get a message sent to a object with a bogus selector. */
  356.   assert(runtimeInitialized);
  357.  
  358.   /* Objective-C allows messages to be sent to a nil object. */
  359.   if (theReceiver) {
  360.  
  361.     /* Check for common programmer error. */
  362.     if (!theReceiver->isa) {
  363.       fprintf (stderr, "method %s sent to deallocated object %#x\n", 
  364.         sel_getName (aSel), theReceiver);
  365.       abort ();
  366.     }
  367.     
  368.         /* Initialize the class if need be. */
  369.         if( !( theReceiver->isa->info & CLS_INITIALIZED ))
  370.             initializeClass (theReceiver->isa->name);
  371.  
  372.     /*
  373.      * If we're passed a object then its isa is a Class.  If
  374.      * we're passed a Class then its isa is a MetaClass. 
  375.      * Therefore, searching for a instance or class method
  376.      * requires no special decision making here. 
  377.      *
  378.      * Look for the method. 
  379.      */
  380.     theIMP = getIMP (theReceiver->isa, aSel);
  381.  
  382.     /* If the method cannot be found then perform error handling. */
  383.     if (!theIMP)
  384.       theIMP = handleRuntimeError (theReceiver, aSel);
  385.   }
  386.  
  387.   /* Nice debugging messages if enabled. */
  388.   if (objc_trace) {
  389.     printf ("trace: objc_msgSend (), obj=%#x, class=%s, method=%s\n",
  390.       theReceiver, 
  391.       theReceiver->isa->name, 
  392.       sel_getName (aSel));
  393.     fflush (stdout);
  394.   }
  395.   
  396.   return theIMP;
  397. }
  398.  
  399.  
  400. IMP 
  401. objc_msgSendSuper (Super_t superContext, SEL aSel) {
  402.  
  403.   IMP    theIMP;
  404.  
  405.  
  406.   assert(runtimeInitialized);
  407.  
  408.     if( !( superContext->class->info & CLS_INITIALIZED ))
  409.             initializeClass (superContext->class->name);
  410.     if( !( superContext->receiver->isa->info & CLS_INITIALIZED ))
  411.             initializeClass (superContext->receiver->isa->name);
  412.  
  413.   theIMP = getIMP (superContext->class, aSel);
  414.   
  415.   if (!theIMP)
  416.     theIMP = handleRuntimeError (superContext->receiver, aSel);
  417.  
  418.   if (objc_trace) {
  419.     printf ("trace: objc_msgSendSuper (), obj=%#x, class=%s, method=%s\n",
  420.       superContext->receiver, 
  421.       superContext->receiver->isa->name, 
  422.       sel_getName (aSel));
  423.     fflush (stdout);
  424.   }
  425.  
  426.   return theIMP;
  427. }
  428.  
  429.  
  430. /*
  431.  * This function is called by objc_msgSend() or objc_msgSendSuper() when a
  432.  * message is sent to a object which it does not recognize. 
  433.  */
  434. static IMP  
  435. handleRuntimeError (id theObject, SEL aSel) {
  436.  
  437.   IMP    theIMP;
  438.  
  439.  
  440.   /*
  441.    * If the object recognizes the doesNotRecognize: method then we're
  442.    * going to send it. 
  443.    */
  444.   theIMP = getIMP (theObject->isa, sel_getUid ("doesNotRecognize:"));
  445.   if (theIMP)
  446.     errorStatic = (*theIMP)(theObject, sel_getUid ("doesNotRecognize:"), aSel);
  447.   else {
  448.     /*
  449.      * The object doesn't recognize the method.  Check for
  450.      * responding to error:.  If it does then sent it. 
  451.      */
  452.     char msg[ 256 
  453.          + strlen (sel_getName (aSel)) 
  454.          + strlen (theObject->isa->name) ];
  455.         
  456.     sprintf (msg, "%s does not recognize %s", 
  457.       theObject->isa->name, sel_getName (aSel));
  458.         
  459.     theIMP = getIMP (theObject->isa, sel_getUid ("error:"));
  460.     if (theIMP)
  461.       errorStatic = (*theIMP)(theObject, sel_getUid ("error:"), msg);
  462.     else {
  463.       /*
  464.        * The object doesn't respond to doesNotRecognize: or
  465.        * error:;  Therefore, a default action is taken. 
  466.        */
  467.       fprintf (stderr, "%s\n", msg);
  468.       abort ();
  469.     }
  470.   }
  471.  
  472.   /*
  473.    * Either doesNotRecognize: or error: has been overridden.  We have
  474.    * to return that value as the default action. 
  475.    */
  476.   return returnErrorStaticIMP;
  477. }
  478.  
  479.  
  480. /*
  481.  * This function is used by the run-time to provide a method where nil
  482.  * objects can receive messages. 
  483.  *
  484.  * This method simply returns self. 
  485.  */
  486. static id  
  487. nilMethodIMP (id aObject, SEL aSel, ...) {
  488.  
  489.  
  490.   return aObject;
  491. }
  492.  
  493.  
  494. /*
  495.  * This function is used by the run-time to provide a method where nil
  496.  * objects can receive messages. 
  497.  *
  498.  * This method simply returns self. 
  499.  *
  500.  * Note: multiple thread problem area. 
  501.  */
  502. static id  
  503. returnErrorStaticIMP (id aObject, SEL aSel, ...) {
  504.  
  505.  
  506.   return errorStatic;
  507. }
  508.  
  509.  
  510. /*
  511.  * These variables provide a way for the defalut methods of object
  512.  * allocation, destruction, and reallocation to be overridden. 
  513.  */
  514.   id    (*_alloc)(Class_t)                  = objc_object_create;
  515.   id    (*_dealloc)(id)                     = objc_object_dispose;
  516.   id    (*_realloc)(id, u_int)              = objc_object_realloc;
  517.   id    (*_copy)(id)                        = objc_object_copy;
  518.   void  (*_error)(id, const char*, va_list) = objc_error;
  519.  
  520.  
  521. id 
  522. objc_object_create (Class_t aClass) {
  523.  
  524.   id        aObject;
  525.  
  526.   
  527.     assert( aClass );
  528.  
  529.   /*
  530.    * Allocate memory for the object, initialize the memory to 0, and
  531.    * set the object's isa pointer. 
  532.    *
  533.    * The object's isa pointer is the class's TEXT image.  It is used by
  534.    * the messager as the key to the class hash for methods. 
  535.    *
  536.    * No need to initialize the class.  That was done in objcInit(). 
  537.    */
  538.   aObject = calloc (1, aClass->instance_size);
  539.   assert(aObject);
  540.   aObject->isa = aClass;
  541.  
  542.   return aObject;
  543. }
  544.  
  545.  
  546. id  
  547. objc_object_dispose (id aObject) {
  548.  
  549.  
  550.   aObject->isa = NULL;
  551.   free (aObject);
  552.  
  553.   return nil;
  554. }
  555.  
  556.  
  557. id  
  558. objc_object_realloc (id aObject, u_int numBytes) {
  559.  
  560.   id  reallocObj;
  561.   
  562.   
  563.     /* Can't resize a object smaller than its instance size. */
  564.     assert (numBytes >= aObject->isa->instance_size);
  565.  
  566.   reallocObj = realloc (aObject, numBytes);
  567.   memset (((char*)reallocObj) + aObject->isa->instance_size,  
  568.                     0, (numBytes - aObject->isa->instance_size));
  569.   
  570.   return reallocObj;
  571. }
  572.  
  573.  
  574. id  
  575. objc_object_copy (id aObject) {
  576.  
  577.   id  newObj;
  578.   
  579.   
  580.   newObj = class_createInstance (aObject->isa);
  581.   memcpy (newObj, aObject, objc_classSize (aObject));
  582.   
  583.   return newObj;
  584. }
  585.  
  586.  
  587. void  
  588. objc_error (id aObject, const char* fmt, va_list ap) {
  589.  
  590.  
  591.   vfprintf (stderr, fmt, ap);
  592.   abort ();
  593. }
  594.  
  595.  
  596. /* Silly function to skip past a sequence of digits in a string.  */
  597. static inline const char*
  598. skipDigits (const char* str) {
  599.  
  600.   while (isdigit (*str))
  601.     ++str;
  602.  
  603.   return str;
  604. }
  605.  
  606.  
  607. u_int 
  608. method_getNumberOfArguments (Method_t aMethod) {
  609.  
  610.   u_int       num = 0;
  611.   const char* args = &aMethod->method_types[1];
  612.   
  613.   
  614.   while (*args) {
  615.   
  616.     /* Skip past size info. */
  617.     args = skipDigits (args);
  618.     
  619.     /* Argument type next. */
  620.     assert(*args);
  621.     ++num;
  622.     
  623.     /* Step to next arg. */
  624.     ++args;
  625.   }
  626.   
  627.   assert(num >= 2);
  628.   return num;
  629. }
  630.  
  631.  
  632. u_int 
  633. method_getArgumentInfo (Method_t aMethod, int indx, const char **type, 
  634.             int *offset) {
  635.  
  636.   const char* args = skipDigits (&aMethod->method_types[1]);
  637.   int         i;
  638.  
  639.   
  640.   assert(method_getNumberOfArguments (aMethod) >= indx);
  641.  
  642.   /* Step to arg. */
  643.   for (i = 0; i < indx; ++i) {
  644.     ++args;
  645.     args = skipDigits (args);
  646.   }
  647.   
  648.   /* Return arg data. */
  649.   *type = args++;
  650.   *offset = atoi (args);
  651.   
  652.   return indx;
  653. }
  654.  
  655.  
  656. /* This function is not thread safe. */
  657. Ivar_t  
  658. object_getIvarAddress (id aObject, const char* variableName) {
  659.  
  660.   Class_t scanClass = aObject->isa; /* Here is the thread safe problem. */
  661.   Ivar_t  theIvarSought = NULL;
  662.   
  663.  
  664.   do {
  665.     IvarList_t  ivarList = scanClass->ivars;
  666.     int         i;
  667.       
  668.     /* Look at all of the ivar names. */
  669.     for (i = 0; i < ivarList->ivar_count; ++i)
  670.       if (!strcmp (variableName, ivarList->ivar_list[ i ].ivar_name))
  671.         theIvarSought = &ivarList->ivar_list[ i ];
  672.            
  673.     /*
  674.      * If the ivar wasn't found then lets look to the
  675.      * super class. 
  676.      *
  677.      * If the class is Object then the super class is NULL
  678.      * and we're done. 
  679.      */
  680.     scanClass = scanClass->super_class;
  681.         
  682.   } while (!theIvarSought && scanClass);
  683.  
  684.   return theIvarSought;
  685. }
  686.  
  687.  
  688. /*
  689.  * Search for a method starting from the current class up its hierarchy.  
  690.  *
  691.  * Return a pointer to the method's method structure if found.  NULL otherwise. 
  692.  */
  693. Method_t  
  694. searchForMethodInHierarchy (Class_t aClass, SEL aSel) {
  695.  
  696.   Method_t      theMethodSought = NULL;
  697.   const char*    selName = sel_getName (aSel);
  698.  
  699.  
  700.   /*
  701.    * Scan the method list of the class.  If the method isn't found in
  702.    * the list then step to its super class. 
  703.    */
  704.   do {
  705.     
  706.     theMethodSought = searchForMethodInList (aClass->methods, selName);
  707.     aClass = aClass->super_class;
  708.  
  709.   } while (!theMethodSought && aClass);
  710.     
  711.   return theMethodSought;
  712. }
  713.  
  714.  
  715. /*
  716.  * Given a linked list of method and a method's name.  Search for the named
  717.  * method's method structure. 
  718.  *
  719.  * Return a pointer to the method's method structure if found.  NULL otherwise. 
  720.  */
  721. Method_t  
  722. searchForMethodInList (MethodList_t aList, const char* selName) {
  723.  
  724.   MethodList_t  aMethodList = aList;
  725.   
  726.  
  727.   /* Check for bumbling. */
  728.   assert(selName);
  729.  
  730.   /* If not found then we'll search the list. */
  731.   while (aMethodList) {
  732.     int   i;
  733.   
  734.     /* Search the method list. */
  735.     for (i = 0; i < aMethodList->method_count; ++i) {
  736.       Method_t aMethod = &aMethodList->method_list[ i ];
  737.  
  738.       if (aMethod->method_name)
  739.     if (!strcmp (aMethod->method_name, selName))
  740.       return aMethod;
  741.     }
  742.         
  743.     /* The method wasn't found.  Follow the link to the next list of 
  744.        methods. */
  745.     aMethodList = aMethodList->method_next;
  746.   }
  747.   
  748.   return NULL;
  749. }
  750.  
  751.  
  752. /*
  753.  * This function adds a method list to a class.  
  754.  *
  755.  * This function is typically called by another function specific to the
  756.  * run-time.  As such this function does not worry about thread safe issued.  
  757.  */
  758. void  
  759. addMethodsToClass (Class_t aClass, MethodList_t newList) {
  760.  
  761.   int i;
  762.   
  763.   
  764.   /* Passing of a linked list is not allowed.  Do multiple calls. */
  765.   assert(!newList->method_next);
  766.  
  767.   /* Check for duplicates. */ 
  768.   for (i = 0; i < newList->method_count; ++i) {
  769.     Method_t  aMethod = &newList->method_list[i];
  770.  
  771.     if (aMethod->method_name) /* Sometimes these are NULL */
  772.       if (searchForMethodInList (aClass->methods, aMethod->method_name)) {
  773.     /*
  774.      * Duplication. Print a error message an change the
  775.      * method name to NULL. 
  776.      */
  777.     fprintf (stderr, "attempt to add a existing method: %s\n",
  778.          aMethod->method_name);
  779.     aMethod->method_name = NULL;
  780.       }
  781.   }
  782.   
  783.   /* Add the methods to the class's method list. */
  784.   newList->method_next = aClass->methods;
  785.   aClass->methods = newList;
  786. }
  787.  
  788.  
  789. /*
  790.  * This function removes the instance and factory methods in the passed list
  791.  * from a class.  
  792.  *
  793.  * Methods are removed from a class by replacing the method's name with NULL. 
  794.  *
  795.  *
  796.  * This function is typically called by another function specific to the
  797.  * run-time.  As such this function does not worry about thread safe issued.  
  798.  */
  799. void  
  800. class_removeMethods (Class_t aClass, MethodList_t aMethodList) {
  801.  
  802.   int i;
  803.   
  804.   
  805.   /* Passing of a linked list is not allowed.  Do multiple calls. */
  806.   assert(!aMethodList->method_next);
  807.  
  808.   /*
  809.    * For each method in the list search the method lists erasing any
  810.    * entries found. 
  811.    */
  812.   for (i = 0; i < aMethodList->method_count; ++i) {
  813.     Method_t  killMethod = &aMethodList->method_list[i];
  814.     Method_t  aMethod;
  815.  
  816.     /* Remove any instance method found. */
  817.     aMethod = searchForMethodInList (aClass->methods, 
  818.                      killMethod->method_name);
  819.     if (aMethod)
  820.       aMethod->method_name = NULL;
  821.       
  822.     /* Remove any factory method found. */
  823.     aMethod = searchForMethodInList (aClass->isa->methods, 
  824.                      killMethod->method_name);
  825.     if (aMethod)
  826.       aMethod->method_name = NULL;
  827.   }
  828. }
  829.  
  830.  
  831. /*
  832.  * This is a incomplete implementation of posing.   This function does the
  833.  * bulk of the work but does not initialize the class method caches.  That is
  834.  * a run-time specific operation. 
  835.  *
  836.  * I implement posing by hiding theSuperClass, creating new class and meta
  837.  * class structures, initializing it with theImposter, and changing it such
  838.  * that it is identified as theSuperClass. theSuperClass remains in the
  839.  * hierarchy but is inaccessible by the means. The class hierarchy is then re
  840.  * arranged such that all of the subclasses of theSuperClass now inherit from
  841.  * the new class structures -- except the impostor itself. The only dramatic
  842.  * effect on the application is that subclasses of theSuperClass cannot do a 
  843.  * [ ....  superClass ] and expect their real super class. 
  844.  */
  845. Class_t 
  846. class_poseAs (Class_t theImpostor, Class_t theSuperClass) {
  847.  
  848.   Class_t     newClass = calloc (1, sizeof (Class));
  849.   MetaClass_t newMetaClass = calloc (1, sizeof (MetaClass));
  850.     CacheNode_t    aNode;
  851.   char*       newName = malloc (strlen (theSuperClass->name) + 12);
  852.  
  853.   
  854.   assert(newClass);
  855.   assert(newMetaClass);
  856.   assert(newName);
  857.  
  858.     /* No dispatching while the the posing class is being built.
  859.         The dispatch tables will be hacked on. */
  860.     MUTEX_LOCK( runtimeMutex );
  861.     
  862.   assert(theImpostor->info & CLS_CLASS);
  863.   assert(theSuperClass->info & CLS_CLASS);
  864.  
  865.   assert(theImpostor->instance_size == theSuperClass->instance_size);
  866.  
  867.   /* Create the impostor class. */
  868.   newClass->isa               = newMetaClass;
  869.   newClass->super_class       = theSuperClass;
  870.   newClass->name              = theSuperClass->name;
  871.   newClass->version           = theSuperClass->version;
  872.   newClass->info              = theSuperClass->info;
  873.   newClass->instance_size     = theSuperClass->instance_size;
  874.   newClass->ivars             = theSuperClass->ivars;
  875.   newClass->methods           = theImpostor->methods;
  876.   newClass->cache                            = &instanceMethodRecord;
  877.   
  878.   /* Create the impostor meta class. */
  879.   newMetaClass->isa           = theSuperClass->isa->isa;
  880.   newMetaClass->super_class   = theSuperClass->isa->super_class;
  881.   newMetaClass->name          = theSuperClass->isa->name;
  882.   newMetaClass->version       = theSuperClass->isa->version;
  883.   newMetaClass->info          = theSuperClass->isa->info;
  884.   newMetaClass->instance_size = theSuperClass->isa->instance_size;
  885.   newMetaClass->ivars         = theSuperClass->isa->ivars;
  886.   newMetaClass->methods       = theImpostor->isa->methods;
  887.   newMetaClass->cache                    = &factoryMethodRecord;
  888.  
  889.     /*
  890.      * Delete the class from the hash table, change its name so that it
  891.      * can no longer be found, then place it back into the hash table
  892.      * using its new name. 
  893.      *
  894.      * Don't worry about the class number.  It is already assigned. 
  895.      *
  896.      * Don't worry about dangling pointers.  Life's a bitch.  (A little bit
  897.      * of memory is lost with the hash key.)
  898.      */
  899.     hash_remove (classHash, theSuperClass->name);
  900.   sprintf (newName, "%s*", theSuperClass->name);
  901.   theSuperClass->name       = newName;
  902.   theSuperClass->isa->name  = newName;
  903.     hash_add (&classHash, theSuperClass->name, theSuperClass);
  904.   
  905.   /*
  906.    * Now change all of the classes derived from theSuperClass to be
  907.    * derived from a impostor (except the impostor's impostor. 
  908.    */
  909.     for (aNode = hash_next (classHash, NULL); aNode;
  910.         aNode = hash_next (classHash, aNode)) {
  911.         
  912.     Class_t    theClass = aNode->theValue;
  913.     
  914.     if (theClass->super_class == theSuperClass)
  915.       if (theClass != theImpostor)
  916.         theClass->super_class = newClass;
  917.   }
  918.  
  919.   /* Place the impostor class in class hash table
  920.         and assign it a class number. */
  921.   addClassToHash (newClass);
  922.  
  923.   /* Reinitialize the dispatch tables. */
  924.   initializeDispatchTables ();
  925.  
  926.     MUTEX_UNLOCK( runtimeMutex );
  927.  
  928.   /* Print out class tables if debugging. */
  929.   DEBUG_PRINTF (stderr, "dump of class tables class_poseAs()\n");
  930.   debug_dump_classes();
  931.  
  932.   return newClass;
  933. }
  934.  
  935.  
  936. /*
  937.  * This routine is given a class and records all of the methods in its class
  938.  * structure in the record table.  
  939.  */
  940. static void
  941. recordMethodsFromClass (Class_t aClass) {
  942.  
  943.   MethodList_t    methodList;
  944.     
  945.     
  946.   methodList = aClass->methods;
  947.   while(methodList) {
  948.     recordMethodsFromMethodList(methodList);
  949.     methodList = methodList->method_next;
  950.   }
  951. }
  952.  
  953.  
  954. /*
  955.  * This routine is given a list of methods and records each of the methods in
  956.  * the record table.  This is the routine that does the actual recording
  957.  * work. 
  958.  */
  959. static void
  960. recordMethodsFromMethodList (MethodList_t aMethodList) {
  961.  
  962.   int    i;
  963.     
  964.     
  965.   for(i = 0; i < aMethodList->method_count; ++i) {
  966.     Method_t aMethod = &aMethodList->method_list[ i ];
  967.  
  968.     recordSelector(aMethod->method_name);
  969.   }
  970. }
  971.  
  972.  
  973. SEL
  974. sel_getUid (const STR aName) {
  975.  
  976.   int i;
  977.     
  978.     
  979.   for (i = 1; i <= record_entries (selectorRecord); ++i)
  980.     if (!strcmp (aName, record_get (i, selectorRecord)))
  981.       return (SEL)i;
  982.     
  983.   /* Unable to locate selector.  Return error value. */
  984.   return (SEL)0;
  985. }
  986.  
  987.  
  988. const STR
  989. sel_getName (SEL aSelector) {
  990.  
  991.  
  992.   return record_get ((u_int)aSelector, selectorRecord);
  993. }
  994.  
  995.  
  996. /*
  997.  * Store the passed selector name in the selector record and return its
  998.  * selector value (value returned by sel_getUid()). 
  999.  */
  1000. static SEL
  1001. recordSelector (const char* aSel) {
  1002.  
  1003.   int j;
  1004.     
  1005.             
  1006.   /* Find either the selector in the table or an empty slot. */
  1007.   for (j = 1; j <= record_entries (selectorRecord); ++j)
  1008.     if (!strcmp (aSel,  record_get (j, selectorRecord)))
  1009.       return (SEL)j;
  1010.             
  1011.   /* Save the selector name. */
  1012.   record_store (strdup (aSel), selectorRecord);
  1013.   DEBUG_PRINTF (stderr, "Record: %s as: %#x\n", aSel, j);
  1014.  
  1015.   return (SEL)j;        
  1016. }
  1017.  
  1018.  
  1019. /*
  1020.  * Initialize the dispatch tables.  This requires the initialization of the
  1021.  * instanceMethodRecord and factoryMethodRecord arrays and the arrays they
  1022.  * point to. 
  1023.  *
  1024.  * The first array is indexed by a class number.  Therefore its size is the
  1025.  * number of classes in the executable.  The second array is indexed by a
  1026.  * selector id.  Therefore its size is the number of unique selectors in the
  1027.  * application. 
  1028.  *
  1029.  * When a method is sent to a object its class number is extracted from the
  1030.  * class structure and used in the first array.  The selector id is used in
  1031.  * the second.  The result value is a method implementation. 
  1032.  */
  1033. static void
  1034. initializeDispatchTables (void) {
  1035.  
  1036.   int    i;
  1037.  
  1038.  
  1039.   /* Check to make sure things are in place. */
  1040.   assert(selectorRecord);
  1041.  
  1042.   /* Blow away the instance and factory method records. */
  1043.   if (factoryMethodRecord) {
  1044.     for (i = 1; i <= record_entries (factoryMethodRecord); ++i)
  1045.       record_delete (record_get(i, factoryMethodRecord));
  1046.     record_delete (factoryMethodRecord);
  1047.   }
  1048.   if (instanceMethodRecord) {
  1049.     for (i = 1; i <= record_entries (instanceMethodRecord); ++i)
  1050.       record_delete (record_get(i, instanceMethodRecord));
  1051.     record_delete (instanceMethodRecord);
  1052.   }
  1053.  
  1054.   /* Reallocate the instance and factory method records. */
  1055.   factoryMethodRecord = record_new ();
  1056.   instanceMethodRecord = record_new ();
  1057.   for (i = 1; i <= record_entries (selectorRecord); ++i) {
  1058.     record_store (record_new(), factoryMethodRecord);
  1059.     record_store (record_new(), instanceMethodRecord);
  1060.   }
  1061.     
  1062.   /* Fool all of the secondary records into thinking they have data. */
  1063.   for (i = 1; i <= record_entries (selectorRecord); ++i) {
  1064.     Record_t         aRecord;
  1065.         CacheNode_t    aNode;
  1066.     
  1067.     aRecord = record_get (i, factoryMethodRecord);
  1068.         for (aNode = hash_next (moduleHash, NULL); aNode;
  1069.             aNode = hash_next (moduleHash, aNode))
  1070.       record_store (NULL, aRecord);
  1071.             
  1072.     aRecord = record_get (i, instanceMethodRecord);
  1073.         for (aNode = hash_next (moduleHash, NULL); aNode;
  1074.             aNode = hash_next (moduleHash, aNode))
  1075.       record_store (NULL, aRecord);
  1076.   }    
  1077.     
  1078.   /* For all classes fill in the methods implemented by the class and visiable
  1079.      from the class in the hierarchy.  Those methods are assigned to the
  1080.      class. */
  1081.   for (i = 1; i <= record_entries (selectorRecord); ++i) { /* i is a sel */
  1082.         CacheNode_t    aNode;
  1083.     
  1084.         for (aNode = hash_next (classHash, NULL); aNode;
  1085.             aNode = hash_next (classHash, aNode)) {
  1086.       Class_t     aClass = aNode->theValue;
  1087.       MetaClass_t aMetaClass = aClass->isa;
  1088.             int                    classNum = getClassNumber (aClass);
  1089.       Method_t    aMethod;
  1090.  
  1091.             /* DEBUG_PRINTF (stderr, "Assignment of sel=%s, class=%s (%#x, %#x)\n", 
  1092.             sel_getName ((SEL)i), aClass->name,
  1093.             searchForMethodInHierarchy (aClass, (SEL)i),
  1094.             searchForMethodInHierarchy ((Class_t)aMetaClass, (SEL)i)); */
  1095.  
  1096.       aMethod = searchForMethodInHierarchy (aClass, (SEL)i);
  1097.       if (aMethod)
  1098.                 record_store_at (classNum, aMethod->method_imp,
  1099.                      record_get (i, instanceMethodRecord));
  1100.  
  1101.       assert( classNum == getClassNumber ((Class_t)aClass->isa));
  1102.       aMethod = searchForMethodInHierarchy ((Class_t)aMetaClass, (SEL)i);
  1103.       if (aMethod)
  1104.         record_store_at (classNum, aMethod->method_imp,
  1105.                          record_get (i, factoryMethodRecord));
  1106.     }
  1107.   }
  1108. }
  1109.  
  1110.  
  1111. /*
  1112.  * This method is called by the dispatch routines when a class has not been
  1113.  * initialized.  This method is responsible for initializing the class.  This
  1114.  * is accomplished by first testing the class itself for responding to the
  1115.  * +initialize method.  If such a method is implemented then it is called. 
  1116.  * Before exit, irregardless if the class implements +initialize, the class
  1117.  * is marked as initialized. 
  1118.  */
  1119. static void        
  1120. initializeClass (const char* theClassName) {
  1121.  
  1122.  
  1123.   Method_t    theMethodSought = NULL;
  1124.     Class_t        theClass = objc_getClass (theClassName);
  1125.     SEL                theSel = sel_getUid ("initialize");
  1126.  
  1127.     
  1128.     /* The class should not be initialized at this point. */
  1129.     assert( !(theClass->info & CLS_INITIALIZED ));
  1130.     assert( !(theClass->isa->info & CLS_INITIALIZED ));
  1131.  
  1132.     /* Search for the +initialize method.
  1133.         Call it if it exists. */
  1134.     theMethodSought = 
  1135.         searchForMethodInList (theClass->isa->methods, sel_getName (theSel));
  1136.     if (theMethodSought) {
  1137.         IMP    theIMP;
  1138.  
  1139.       DEBUG_PRINTF (stderr, "Class: %s sending +%s\n", 
  1140.                                     theClassName, sel_getName (theSel));
  1141.         theIMP = getIMP ((Class_t)theClass->isa, theSel);
  1142.         assert(theIMP);
  1143.         (*theIMP)(theClass, theSel);
  1144.     }
  1145.  
  1146.     /* Mark the class as initialized. */
  1147.     theClass->info            |= CLS_INITIALIZED;
  1148.     theClass->isa->info    |= CLS_INITIALIZED;
  1149. }
  1150.  
  1151.  
  1152. /*
  1153.  * Silly little function that checks to make sure the class hash table is
  1154.  * initialized.  If it isn't initialized then do it. 
  1155.  */
  1156. static inline void
  1157. classHashInit( void ) {
  1158.  
  1159.     static u_int    init = 0;
  1160.     
  1161.     
  1162.     if( !init )
  1163.         classHash = hash_new(CLASS_HASH_SIZE, 
  1164.                                                 (HashFunc)strHash, (CompareFunc)strCmp);
  1165.     init = 1;
  1166. }
  1167.  
  1168.  
  1169. Class_t 
  1170. objc_getClass( const char* aClassName) {
  1171.  
  1172.     Class_t    aClass;
  1173.  
  1174.  
  1175.     /* Make sure the class hash table exists. */
  1176.     classHashInit();
  1177.  
  1178.     aClass = hash_value_for_key( classHash, aClassName );
  1179.     
  1180.     return aClass;
  1181. }
  1182.  
  1183.  
  1184. MetaClass_t 
  1185. objc_getMetaClass( const char* aClassName) {
  1186.  
  1187.     
  1188.     /* Meta classes are pointed to by the class's isa.
  1189.         Just get the class and return its isa. */
  1190.     return( objc_getClass( aClassName ))->isa;
  1191. }
  1192.  
  1193.  
  1194. void
  1195. addClassToHash(Class_t aClass) {
  1196.  
  1197.     Class_t    hClass;
  1198.     
  1199.     
  1200.     classHashInit();
  1201.  
  1202.     /* Check to see if the class is already in the hash table. */
  1203.     hClass = hash_value_for_key( classHash, aClass->name);
  1204.     if( !hClass ) {
  1205.                                                                                                 /* The class isn't in the hash
  1206.                                                                                                     table.  Add the class and 
  1207.                                                                                                     assign a class number. */
  1208.         static u_int    classNum = 1;
  1209.     
  1210.         setClassNumber( aClass, classNum);
  1211.         setClassNumber((Class_t)aClass->isa, classNum);
  1212.         ++classNum;
  1213.         
  1214.         hash_add( &classHash, aClass->name, aClass);
  1215.     }
  1216. }
  1217.  
  1218.  
  1219. void  
  1220. debug_dump_classes( void) {
  1221.  
  1222.   CacheNode_t aNode;
  1223.   int         i;
  1224.  
  1225.  
  1226.   DEBUG_PRINTF( stderr, "class tables\n");
  1227.   i = 0;
  1228.   for( aNode = hash_next( classHash, NULL); aNode; 
  1229.     aNode = hash_next( classHash, aNode)) {
  1230.  
  1231.     Class_t theClass = aNode->theValue;
  1232.       
  1233.     DEBUG_PRINTF( stderr, 
  1234.         "Class { /*%#x*/\n", theClass);
  1235.     DEBUG_PRINTF( stderr, 
  1236.         "   MetaClass_t  isa           = %#x\n", theClass->isa);
  1237.     DEBUG_PRINTF( stderr, 
  1238.         "   Class_t      super_class   = %#x\n", theClass->super_class);
  1239.     DEBUG_PRINTF( stderr, 
  1240.         "   char*        name          = %s\n", theClass->name);
  1241.     DEBUG_PRINTF( stderr, 
  1242.         "   long         version       = %ld\n", theClass->version);
  1243.     DEBUG_PRINTF( stderr, 
  1244.         "   long         info          = %#x\n", theClass->info);
  1245.     DEBUG_PRINTF( stderr, 
  1246.         "   long         instance_size = %ld\n", theClass->instance_size);
  1247.     DEBUG_PRINTF( stderr, 
  1248.         "   IvarList_t   ivars         = %#x\n", theClass->ivars);
  1249.     DEBUG_PRINTF( stderr, 
  1250.         "   MethodList_t methods       = %#x\n", theClass->methods);
  1251.     DEBUG_PRINTF( stderr, 
  1252.         "   Cache_t      cache         = %#x\n", theClass->cache);
  1253.     DEBUG_PRINTF( stderr, "}[%d];\n", i++);
  1254.   }
  1255.     
  1256.   i = 0;
  1257.   for( aNode = hash_next( classHash, NULL); aNode; 
  1258.     aNode = hash_next( classHash, aNode)) {
  1259.  
  1260.     Class_t theClass = (Class_t)((Class_t)(aNode->theValue))->isa;
  1261.       
  1262.     DEBUG_PRINTF( stderr, 
  1263.         "MetaClass { /*%#x*/\n", theClass);
  1264.     DEBUG_PRINTF( stderr, 
  1265.         "   MetaClass_t  isa           = %#x\n", theClass->isa);
  1266.     DEBUG_PRINTF( stderr, 
  1267.         "   MetaClass_t  super_class   = %#x\n", theClass->super_class);
  1268.     DEBUG_PRINTF( stderr, 
  1269.         "   char*        name          = %s\n", theClass->name);
  1270.     DEBUG_PRINTF( stderr, 
  1271.         "   long         version       = %ld\n", theClass->version);
  1272.     DEBUG_PRINTF( stderr, 
  1273.         "   long         info          = %#x\n", theClass->info);
  1274.     DEBUG_PRINTF( stderr, 
  1275.         "   long         instance_size = %ld\n", theClass->instance_size);
  1276.     DEBUG_PRINTF( stderr, 
  1277.         "   IvarList_t   ivars         = %#x\n", theClass->ivars);
  1278.     DEBUG_PRINTF( stderr, 
  1279.         "   MethodList_t methods       = %#x\n", theClass->methods);
  1280.     DEBUG_PRINTF( stderr, 
  1281.         "   Cache_t      cache         = %#x\n", theClass->cache);
  1282.     DEBUG_PRINTF( stderr, "}[%d];\n", i++);
  1283.   }
  1284. }
  1285.  
  1286.